大家好,歡迎來到 FastAPI 系列文章的第 6 天!今天我們要探討另一種平行處理的方式:Thread(執行緒) 和 Process(程序)。
有些地方會把 Thread 翻譯成「線程」,把 Process 翻譯成「進程」。
在 Python 的世界裡,我們有三種主要的並發處理方式:
每種方式都有其獨特的適用場景,理解它們的差異和適用時機是構建高效能 FastAPI 應用的關鍵。
執行緒 是作業系統中最小的執行單位,多個執行緒可以在同一個程序中並行執行。在 Python 中,執行緒特別適合處理 I/O 密集型任務,因為當一個執行緒在等待 I/O 操作時,其他執行緒可以繼續工作。
執行緒最適合以下情況:
在 Python 中,我們使用 threading
模組來操作執行緒:
import threading
import time
import os
def worker(worker_id):
# os.getpid() 取得行程ID,threading.get_ident() 取得執行緒ID
print(f"Worker {worker_id} - Process ID: {os.getpid()}, Thread ID: {threading.get_ident()} - 開始工作")
time.sleep(2)
print(f"Worker {worker_id} - Process ID: {os.getpid()}, Thread ID: {threading.get_ident()} - 完成工作")
if __name__ == "__main__":
print("主執行緒開始")
# 建立兩個執行緒
t1 = threading.Thread(target=worker, args=(1,))
t2 = threading.Thread(target=worker, args=(2,))
# 啟動執行緒
t1.start()
t2.start()
print("主執行緒繼續執行...")
# 等待所有子執行緒結束
t1.join()
t2.join()
print("主執行緒結束")
你會發現,兩個執行緒的 Process ID
都跟主程式是一樣的,但 Thread ID
會不同。
執行緒的優勢在於它能夠有效利用 I/O 等待時間。當一個執行緒在等待網路回應時,CPU 可以切換到其他執行緒繼續工作,從而提高整體效能。
程序 是作業系統中資源分配的基本單位,每個程序都有獨立的記憶體空間。程序間的通訊比執行緒複雜,但它們可以真正並行執行,不受 Python GIL 的限制。
程序最適合以下情況:
import multiprocessing
import time
import os
def worker(worker_id):
# os.getpid() 可以取得當前行程的 ID
print(f"Worker {worker_id} - Process ID: {os.getpid()} - 開始工作")
time.sleep(2)
print(f"Worker {worker_id} - Process ID: {os.getpid()} - 完成工作")
if __name__ == "__main__":
print(f"主行程 - Process ID: {os.getpid()} - 開始")
# 建立兩個程序
p1 = multiprocessing.Process(target=worker, args=(1,))
p2 = multiprocessing.Process(target=worker, args=(2,))
# 啟動程序
p1.start()
p2.start()
print("主行程繼續執行...")
# 等待所有子程序結束
p1.join()
p2.join()
print("主行程結束")
程序的優勢在於它們可以充分利用多核心 CPU,實現真正的平行計算,不受 Python GIL 的限制。你會看到兩個子程序都有不同的 Process ID
,它們是完全獨立運行的。
這是一個經典問題,答案取決於你的「任務類型」:
Thread
或 Asyncio
。當一個執行緒在等待 I/O 時,Python 會把它切換掉,讓 CPU 去執行其他執行緒,從而提升效率。Process
。因為 GIL 的存在,多執行緒對 CPU 密集任務完全沒幫助。必須使用多行程,才能將任務分配到不同 CPU 核心上,實現真正的平行加速。Thread 和 Process 為 FastAPI 提供了處理不同類型工作負載的強大能力。執行緒適合 I/O 密集型任務,程序適合 CPU 密集型任務,而 Asyncio 則適合高併發的 I/O 處理。
理解這三種並發模式的特性和適用場景,能夠幫助我們構建既高效又穩定的 FastAPI 應用。在實際開發中,最好的策略往往是根據具體需求靈活組合使用這些技術。
明天我們將探討 GIL(Global Interpreter Lock),深入了解為什麼在某些情況下執行緒的效能會受到限制,以及如何正確應對這個挑戰!